package com.seari.modbusServer.utils;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.text.SimpleDateFormat;
import java.util.Date;


import com.ghgande.j2mod.modbus.Modbus;
import com.ghgande.j2mod.modbus.ModbusException;
import com.ghgande.j2mod.modbus.ModbusIOException;
import com.ghgande.j2mod.modbus.ModbusSlaveException;
import com.ghgande.j2mod.modbus.io.ModbusTCPTransaction;
import com.ghgande.j2mod.modbus.msg.ReadCoilsRequest;
import com.ghgande.j2mod.modbus.msg.ReadCoilsResponse;
import com.ghgande.j2mod.modbus.msg.ReadInputDiscretesRequest;
import com.ghgande.j2mod.modbus.msg.ReadInputDiscretesResponse;
import com.ghgande.j2mod.modbus.msg.ReadInputRegistersRequest;
import com.ghgande.j2mod.modbus.msg.ReadInputRegistersResponse;
import com.ghgande.j2mod.modbus.msg.ReadMultipleRegistersRequest;
import com.ghgande.j2mod.modbus.msg.ReadMultipleRegistersResponse;
import com.ghgande.j2mod.modbus.msg.WriteCoilRequest;
import com.ghgande.j2mod.modbus.msg.WriteMultipleRegistersRequest;
import com.ghgande.j2mod.modbus.msg.WriteMultipleRegistersResponse;
import com.ghgande.j2mod.modbus.msg.WriteSingleRegisterRequest;
import com.ghgande.j2mod.modbus.net.TCPMasterConnection;
import com.ghgande.j2mod.modbus.procimg.AbstractRegister;
import com.ghgande.j2mod.modbus.procimg.Register;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * ModbusUtil是Modbus的工具类
 * @author Administrator
 *
 */
public class ModbusUtil {
	protected static Logger logger = LoggerFactory.getLogger(ModbusUtil.class);
	/**
	 * 查询Function 为Input Status的寄存器
	 * 
	 * @param ip
	 * @param address
	 * @param count
	 * @param slaveId
	 * @return
	 * @throws ModbusIOException
	 * @throws ModbusSlaveException
	 * @throws ModbusException
	 */
	public static int readDigitalInput(String ip, int port, int address, int slaveId) {
		int data = 0;

		try {
			InetAddress addr = InetAddress.getByName(ip);

			// 建立连接
			TCPMasterConnection con = new TCPMasterConnection(addr);
			
			con.setPort(port);
			
			con.connect();

			// 第一个参数是寄存器的地址，第二个参数时读取多少个
			ReadInputDiscretesRequest req = new ReadInputDiscretesRequest(address, 1);
			
			// 这里设置的Slave Id, 读取的时候这个很重要
			req.setUnitID(slaveId);

			ModbusTCPTransaction trans = new ModbusTCPTransaction(con);

			trans.setRequest(req);

			// 执行查询
			trans.execute();

			// 得到结果
			ReadInputDiscretesResponse res = (ReadInputDiscretesResponse) trans.getResponse();

			if(res.getDiscretes().getBit(0)){
				data = 1;
			}

			// 关闭连接
			con.close();

		} catch (Exception e) {
			e.printStackTrace();
		}

		return data;
	}

	public static int readInputRegister(String ip, int port, int address,int slaveId) {
		int data = 0;

		try {
			InetAddress addr = InetAddress.getByName(ip);
			TCPMasterConnection con = new TCPMasterConnection(addr);
			
			//Modbus.DEFAULT_PORT;
			con.setPort(port);
			con.connect();
			
			//这里重点说明下，这个地址和数量一定要对应起来
			ReadInputRegistersRequest req = new ReadInputRegistersRequest(address, 1);
			
			//这个SlaveId一定要正确
			req.setUnitID(slaveId);

			ModbusTCPTransaction trans = new ModbusTCPTransaction(con);

			trans.setRequest(req);

			trans.execute();

			ReadInputRegistersResponse res = (ReadInputRegistersResponse) trans.getResponse();

			data = res.getRegisterValue(0);

			con.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return data;
	}

	
	public static int readDigitalOutput(String ip, int port, int address,int slaveId) {
		int data = 0;
		try {
			InetAddress addr = InetAddress.getByName(ip);

			TCPMasterConnection con = new TCPMasterConnection(addr);
			con.setPort(port);
			con.connect();

			ReadCoilsRequest req = new ReadCoilsRequest(address, 1);

			req.setUnitID(slaveId);

			ModbusTCPTransaction trans = new ModbusTCPTransaction(con);

			trans.setRequest(req);

			trans.execute();

			ReadCoilsResponse res = ((ReadCoilsResponse) trans.getResponse());

			if(res.getCoils().getBit(0)){
				data = 1;
			}

			con.close();

		} catch (Exception ex) {
			ex.printStackTrace();
		}

		return data;
	}

	/**
	 * 
	 * @param ip
	 * @param port
	 * @param address
	 * @param slaveId
	 * @return
	 */
	public static int readRegister(String ip, int port, int address,int slaveId) {
		int data = 0;
		try {
			InetAddress addr = InetAddress.getByName(ip);

			TCPMasterConnection con = new TCPMasterConnection(addr);

			con.setPort(port);
			con.connect();
			ReadMultipleRegistersRequest req = new ReadMultipleRegistersRequest(address,1);
			req.setUnitID(slaveId);
			ModbusTCPTransaction trans = new ModbusTCPTransaction(con);

			trans.setRequest(req);

			trans.execute();

			ReadMultipleRegistersResponse res = (ReadMultipleRegistersResponse) trans.getResponse();
			data = res.getRegisterValue(0);
			con.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return data;
	}
	
	
	/**
	 * 取count个数的数据返回
	 * @param ip
	 * @param port
	 * @param address
	 * @param slaveId
	 * @param count
	 * @return
	 * 
	 */
	
	public static int[] readRegister(String ip, int port, int address,int slaveId,int count) {
		
		int data[] = new int[count];
		TCPMasterConnection con = null;
		try {
			InetAddress addr = InetAddress.getByName(ip);
			/*TCPMasterConnection */
			con = new TCPMasterConnection(addr);
			con.setPort(port);
			//
//			con.setTimeout(3000);
			con.connect();
			int num1 = count/100;
			
			int num2 = count%100;
			
			for(int m=0;m<num1;m++){
				
				ReadMultipleRegistersRequest req = new ReadMultipleRegistersRequest(address+m*100,100);
				
				req.setUnitID(slaveId);
				
				//con.getModbusTransport().writeMessage(req);
				
				ModbusTCPTransaction trans = new ModbusTCPTransaction(con);
				
				trans.setRequest(req);
				
				trans.execute();
				ReadMultipleRegistersResponse res = (ReadMultipleRegistersResponse) trans.getResponse();
				//ReadMultipleRegistersResponse res = (ReadMultipleRegistersResponse) con.getModbusTransport().readResponse();
				Register[] registers = res.getRegisters();
				for(int i=0;i<registers.length;i++){
					data[m*20+i]=registers[i].getValue();
				}
				
			}
			if(num2>0){
				
				ReadMultipleRegistersRequest req = new ReadMultipleRegistersRequest(address+num1*100,num2);
				
				req.setUnitID(slaveId);
				ModbusTCPTransaction trans = new ModbusTCPTransaction(con);
				//trans.setRetries(1);
				trans.setRequest(req);

				trans.execute();

				ReadMultipleRegistersResponse res = (ReadMultipleRegistersResponse) trans.getResponse();
				Register[] registers = res.getRegisters();
				for(int i=0;i<registers.length;i++){
					data[num1*20+i]=registers[i].getValue();
				}
				
			}


			
		} catch (Exception e) {
			//读取异常的时候以-1的数组返回
			System.out.println("读取异常的时候以-1的数组返回------>ip"+ip);
			for(int i=0;i<data.length;i++){
				data[i]=-1;
			}
//			e.printStackTrace();
		}finally{
			if(con!=null){
				con.close();
			}
			
		}
		return data;
	}
        
    public static int[] readRegister(int address, int slaveId, int count, TCPMasterConnection con) throws Exception
    {
        int data[] = new int[count];
        try
        {
            int num1 = count / 100;
            int num2 = count % 100;
            for (int m = 0; m < num1; m++)
            {

                ReadMultipleRegistersRequest req = new ReadMultipleRegistersRequest(address + m * 100, 100);

                req.setUnitID(slaveId);

                //con.getModbusTransport().writeMessage(req);
                ModbusTCPTransaction trans = new ModbusTCPTransaction(con);

                trans.setRequest(req);

                trans.execute();
                ReadMultipleRegistersResponse res = (ReadMultipleRegistersResponse) trans.getResponse();
                //ReadMultipleRegistersResponse res = (ReadMultipleRegistersResponse) con.getModbusTransport().readResponse();
                Register[] registers = res.getRegisters();
                for (int i = 0; i < registers.length; i++)
                {
                    data[m * 100 + i] = registers[i].getValue();
                }

            }
            if (num2 > 0)
            {
                ReadMultipleRegistersRequest req = new ReadMultipleRegistersRequest(address + num1 * 100, num2);

                req.setUnitID(slaveId);
                ModbusTCPTransaction trans = new ModbusTCPTransaction(con);
                //trans.setRetries(1);
                trans.setRequest(req);

                trans.execute();

                ReadMultipleRegistersResponse res = (ReadMultipleRegistersResponse) trans.getResponse();
                Register[] registers = res.getRegisters();
                for (int i = 0; i < registers.length; i++)
                {
                    data[num1 * 100 + i] = registers[i].getValue();
                }
            }
        } catch (Exception e)
        {
            //读取异常的时候以-1的数组返回
            System.out.println("读取异常的时候以-1的数组返回------>ip" + con.getAddress().toString() + ":" + con.getPort() + " slave:" + slaveId);
            for (int i = 0; i < data.length; i++)
            {
                data[i] = -1;
            }
            throw e;
        }
        return data;
    }

    /**
	 * 写入数据到真机，数据类型是RE
	 * 
	 * @param ip
	 * @param port
	 * @param slaveId
	 * @param address
	 * @param value
	 */
	public static void writeRegister(String ip, int port, int slaveId,
			int address, int value) {
                logger.info("write register:ip{},port{},address{},value{}", ip , port  , address , value);
		TCPMasterConnection connection = null;
		
		try {
			InetAddress addr = InetAddress.getByName(ip);

			/*TCPMasterConnection */connection = new TCPMasterConnection(addr);
			connection.setPort(port);
			connection.setTimeout(200);
			connection.connect();

			ModbusTCPTransaction trans = new ModbusTCPTransaction(connection);
			
			UnityRegister register = new UnityRegister(value);

			WriteSingleRegisterRequest req = new WriteSingleRegisterRequest(
					address, register);
			
			req.setUnitID(slaveId);
			trans.setRetries(1);
			trans.setRequest(req);
			logger.info("ModbusSlave: FC" + req.getFunctionCode()
					+ " ref=" + req.getReference() + " value="
					+ register.getValue());
			trans.execute();

			
		} catch (Exception ex) {
			System.out.println("Error in code");
			ex.printStackTrace();
		}finally{
			if(connection!=null){
				connection.close();
			}
		}
	}
	//测试类
	public static void main(String[] args){
		//writeRegister("192.168.1.63",502,1,26,new int[]{2});
		int[] arr = readRegister("192.168.1.10", 502, 0, 255,20);
		
		for(int i=0;i<arr.length;i++){
			System.out.print(arr[i]+" ");
		}
		System.out.println();
		System.out.println(ByteUtil.getHexStr(arr));
	}
	
	public static boolean writeRegister(String ip, int port, int slaveId,
			int address, int[] value) {
		boolean writedFlag = false;
		TCPMasterConnection connection = null;
		try {
			InetAddress addr = InetAddress.getByName(ip);

			/*TCPMasterConnection */connection = new TCPMasterConnection(addr);
			connection.setPort(port);
			connection.setTimeout(200);
			connection.connect();
			ModbusTCPTransaction trans = new ModbusTCPTransaction(connection);
			
			UnityRegister[] register = new UnityRegister[value.length];
			
			for(int i=0;i<value.length;i++){
				register[i]=new UnityRegister(value[i]);
			}
			//UnityRegister register = new UnityRegister(value);

			WriteMultipleRegistersRequest req = new WriteMultipleRegistersRequest(
					address, register);
		
			req.setUnitID(slaveId);
			
			trans.setRetries(1);
			trans.setRequest(req);
//			System.out.println("ModbusSlave: FC" + req.getFunctionCode()
//					+ " ref=" + req.getReference() + " value="
//					+ register.getValue());
			logger.info("ModbusSlave: FC" + req.getFunctionCode()
			+ " ref=" + req.getReference() );
			trans.execute();
			WriteMultipleRegistersResponse resp = (WriteMultipleRegistersResponse)trans.getResponse();
			if(resp.getByteCount()>=value.length){
				writedFlag=true;
			}
			
		} catch (Exception ex) {
			System.out.println("Error in code");
		//ex.printStackTrace();
		}finally{
			if(connection!=null){
				connection.close();
			}
			
		}
		return writedFlag;
	}

	/**
	 * 写入数据到真机的DO类型的寄存器上面
	 * 
	 * @param ip
	 * @param port
	 * @param slaveId
	 * @param address
	 * @param value
	 */
	public static void writeDigitalOutput(String ip, int port, int slaveId,
			int address, int value) {

		try {
			InetAddress addr = InetAddress.getByName(ip);

			TCPMasterConnection connection = new TCPMasterConnection(addr);
			connection.setPort(port);
			connection.connect();

			ModbusTCPTransaction trans = new ModbusTCPTransaction(connection);

			boolean val = true;

			if (value == 0) {
				val = false;
			}

			WriteCoilRequest req = new WriteCoilRequest(address, val);

			req.setUnitID(slaveId);
			trans.setRequest(req);

			trans.execute();
			connection.close();
		} catch (Exception ex) {
			System.out.println("writeDigitalOutput Error in code");
			ex.printStackTrace();
		}
	}

}
